// Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.

// 配置设置
package config

import (
	"encoding/json"
	"fmt"
	"strings"
	"sync"

	"github.com/pkg/errors"
)

type Config struct {
	items map[string]interface{}
	lock  sync.RWMutex
}

// NewConfig get a new Config
func NewConfig(c map[string]interface{}) *Config {
	if c == nil {
		c = make(map[string]interface{})
	}

	return &Config{
		items: c,
	}
}

// TODO: index access for Set & Get is not support

// Get get config info from path
func (c *Config) Get(path string) *Entry {
	c.lock.RLock()
	defer c.lock.RUnlock()

	if len(path) == 0 {
		return &Entry{Val: nil, Err: fmt.Errorf("empty path")}
	}

	b := c.items
	ss := strings.Split(path, ".")
	length := len(ss)

	for i, s := range ss[:length-1] {
		v, ok := b[s]
		if !ok {
			return &Entry{Val: nil, Err: fmt.Errorf("config entry %s not found", strings.Join(ss[:i+1], "."))}
		}
		t, ok := v.(map[string]interface{})
		if !ok {
			return &Entry{Val: nil, Err: fmt.Errorf("config entry assert type error v %#v", v)}
		}
		b = t
	}

	if val, ok := b[ss[length-1]]; ok {
		return &Entry{Val: val, Err: nil}
	} else {
		return &Entry{Val: nil, Err: fmt.Errorf("config entry %s not found", strings.Join(ss, "."))}
	}
}

// Set set config info to path
func (c *Config) Set(path string, v interface{}) error {
	c.lock.Lock()
	defer c.lock.Unlock()

	if len(path) == 0 {
		return errors.New("empty path")
	}

	b := c.items
	ss := strings.Split(path, ".")
	length := len(ss)

	for _, s := range ss[:length-1] {
		vv, ok := b[s]
		if !ok {
			b[s] = make(map[string]interface{})
			vv = b[s]
		}
		t, ok := vv.(map[string]interface{})
		if ok {
			b = t
		}
	}

	b[ss[length-1]] = v

	return nil
}

// ReNew update config info
func (c *Config) ReNew(v map[string]interface{}) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.items = v
}

// MarshalJSON marshal json
func (c *Config) MarshalJSON() ([]byte, error) {
	c.lock.RLock()
	bytes, err := json.Marshal(c.items)
	c.lock.RUnlock()
	return bytes, err
}
